﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DungeonDelver.Common
{
    public class WeightedGenerator<T>:IWeightedGenerator<T>
    {
        private Dictionary<T, uint> theWeights = new Dictionary<T, uint>();
        private uint theTotalWeight = uint.MinValue;

        public T Generate(IRandomNumberGenerator<uint> theRandomNumberGenerator)
        {
            T result = default(T);
            uint theGeneratedValue = theRandomNumberGenerator.Next(uint.MinValue, theTotalWeight);
            foreach (var key in Keys)
            {
                if (this[key] > theGeneratedValue)
                {
                    result = key;
                    break;
                }
                else
                {
                    theGeneratedValue -= this[key];
                }
            }
            return result;
        }

        public IWeightedGenerator<T> Combine(IWeightedGenerator<T> theOther, Func<T, T, T> theKeyLambda)
        {
            WeightedGenerator<T> result = new WeightedGenerator<T>();
            foreach (var first in Keys)
            {
                foreach (var second in theOther.Keys)
                {
                    result[theKeyLambda(first, second)] += this[first] * theOther[second];
                }
            }
            return result;
        }

        public uint this[T theIndex]
        {
            get
            {
                if (!theWeights.ContainsKey(theIndex))
                {
                    return uint.MinValue;
                }
                else
                {
                    return theWeights[theIndex];
                }
            }
            set
            {
                if (theWeights.ContainsKey(theIndex))
                {
                    theTotalWeight -= theWeights[theIndex];
                    theWeights.Remove(theIndex);
                }
                if (value > uint.MinValue)
                {
                    theWeights.Add(theIndex, value);
                    theTotalWeight += value;
                }
            }
        }

        public IEnumerable<T> Keys
        {
            get { return theWeights.Keys; }
        }


        public void Clear()
        {
            theWeights.Clear();
        }


        public Dictionary<T, uint> Table
        {
            get
            {
                return new Dictionary<T, uint>(theWeights);
            }
            set
            {
                if (value == null)
                {
                    theWeights.Clear();
                }
                else
                {
                    theWeights = new Dictionary<T, uint>(value);
                }
            }
        }

        public WeightedGenerator()
        {
        }

        public WeightedGenerator(Dictionary<T,uint> theTable)
        {
            Table = theTable;
        }
    }
}
